package com.leenmvc.core.dao.sqlServer.mybatis;

import com.leenmvc.core.cache.CacheFactory;
import com.leenmvc.core.dao.communal.Dialect;
import com.leenmvc.core.exception.DaoException;
import com.leenmvc.core.init.Constant;
import com.leenmvc.core.security.User;
import com.leenmvc.core.security.entity.core.SysLogSql;
import com.leenmvc.core.utils.logger.LogEntityPool;
import com.leenmvc.core.utils.thread.ThreadLocalManager;
import com.leenmvc.core.utils.thread.runnables.LogToDb;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * SqlSession配置
 */
public class MybatisQuery {

    private final static Logger logger = LoggerFactory.getLogger(MybatisQuery.class);

    /**
     * 使用Mybatis获取记录
     *
     * @param <T>
     * @return
     */
    public static <T> List<T> listBySqlKey(Class<?> cls, String key, Map<String, Object> params) {
        SqlSession sqlSession = Dialect.SQL_SERVER.getConnectionFactory().getSqlSessionFactory(cls).openSession();
        String ibatisKey = cls.getName() + "." + key;
        List<T> objects = executeForList(sqlSession, ibatisKey, params);
        sqlSession.close();
        return objects;
    }


    /**
     * 使用Mybatis获取记录列表
     *
     * @param <T>
     * @return
     */
    public static <T> List<T> executeForList(SqlSession sqlSession, String ibatisKey, Object params) {
        long start = System.currentTimeMillis();
        List<T> objects = sqlSession.selectList(ibatisKey, params);
        SqlSource sqlSource = sqlSession.getConfiguration().getMappedStatement(ibatisKey).getSqlSource();
        BoundSql boundSql = sqlSource.getBoundSql(params);
        String sql = boundSql.getSql();
        logger.info("执行获取列表的方法，本次执行的sql语句是：{}", sql);
        logger.info("执行获取列表的方法，本次执行的参数是：{}", params);
        if(ThreadLocalManager.isLog() == 0 && CacheFactory.getStatus("SAVE_QUERYSQL_LOG")) {
            SysLogSql logSql = LogEntityPool.getLogSql();
            logSql.setSqlStr(sql);
            logSql.setParams(params.toString());
            logSql.setUsername(User.getUsername());
            logSql.setExcuteTime((int) (System.currentTimeMillis() - start));
            logSql.setCreateDate(new Date());
            logSql.setInfluence(0);
            logSql.setNote(String.valueOf(ThreadLocalManager.get(Constant.CONTROLLER_NOTE)));
            logSql.setUri(String.valueOf(ThreadLocalManager.get("uri")));
            LogToDb.addSqllog(logSql);
        }
        return objects;
    }


    /**
     * 使用Mybatis获取一条记录
     *
     * @param <T>
     * @return
     */
    public static <T> T executeForOne(SqlSession sqlSession, String ibatisKey, Object params) {
        long start = System.currentTimeMillis();
        T object = sqlSession.selectOne(ibatisKey, params);
        SqlSource sqlSource = sqlSession.getConfiguration().getMappedStatement(ibatisKey).getSqlSource();
        BoundSql boundSql = sqlSource.getBoundSql(params);
        String sql = boundSql.getSql();
        logger.info("执行获取列表的方法，本次执行的sql语句是：{}", sql);
        logger.info("执行获取列表的方法，本次执行的参数是：{}", params);
        if(ThreadLocalManager.isLog() == 0 && CacheFactory.getStatus("SAVE_QUERYSQL_LOG")) {
            SysLogSql logSql = LogEntityPool.getLogSql();
            logSql.setSqlStr(sql);
            logSql.setParams(params.toString());
            logSql.setUsername(User.getUsername());
            logSql.setExcuteTime((int) (System.currentTimeMillis() - start));
            logSql.setCreateDate(new Date());
            logSql.setInfluence(0);
            logSql.setNote(String.valueOf(ThreadLocalManager.get(Constant.CONTROLLER_NOTE)));
            logSql.setUri(String.valueOf(ThreadLocalManager.get("uri")));
            LogToDb.addSqllog(logSql);
        }
        return object;
    }


    /**
     * 使用Mybatis获取记录
     *
     * @param <T>
     * @return
     */
    public static <T> List<T> listBySqlKey(Class<?> cls, String key, Object params) {
        SqlSession sqlSession = Dialect.SQL_SERVER.getConnectionFactory().getSqlSessionFactory(cls).openSession();
        String ibatisKey = cls.getName() + "." + key;
        List<T> objects = executeForList(sqlSession, ibatisKey, params);
        sqlSession.close();
        return objects;
    }

    /**
     * 使用Mybatis获取一条记录
     *
     * @param <T>
     * @return
     */
    public static <T> T getBySqlKey(Class<?> cls, String key, Map<String, Object> params) {
        SqlSession sqlSession = Dialect.SQL_SERVER.getConnectionFactory().getSqlSessionFactory(cls).openSession();
        String ibatisKey = cls.getName() + "." + key;
        T object = executeForOne(sqlSession, ibatisKey, params);
        sqlSession.close();
        return object;
    }

    /**
     * 使用Mybatis获取一条记录
     *
     * @param <T>
     * @return
     */
    public static <T> T getBySqlKey(Class<?> cls, String key, Object param) {
        SqlSession sqlSession = Dialect.SQL_SERVER.getConnectionFactory().getSqlSessionFactory(cls).openSession();
        String ibatisKey = cls.getName() + "." + key;
        T object = executeForOne(sqlSession, ibatisKey, param);
        sqlSession.close();
        return object;
    }

    /**
     * 根据键值对参数获取记录
     *
     * @param cls
     * @param key
     * @param KVs
     * @param <T>
     * @return
     */
    public static <T> T getBySqlKey(Class<?> cls, String key, Object...KVs) {
        if(KVs.length % 2 != 0) {
            throw new DaoException("使用Object...KVs的方法，键值对必须成对出现");
        }
        Map<String, Object> params = new HashMap<>();
        for(int i = 0 ; i < KVs.length; i+=2) {
            params.put(String.valueOf(KVs[i]), KVs[i+1]);
        }
        return getBySqlKey(cls, key, params);
    }

    /**
     * 根据键值对参数获取记录列表
     *
     * @param cls
     * @param key
     * @param KVs
     * @param <T>
     * @return
     */
    public static <T> List<T> listBySqlKey(Class<?> cls, String key, Object...KVs) {
        if(KVs.length % 2 != 0) {
            throw new DaoException("使用Object...KVs的方法，键值对必须成对出现");
        }
        Map<String, Object> params = new HashMap<>();
        for(int i = 0 ; i < KVs.length; i+=2) {
            params.put(String.valueOf(KVs[i]), KVs[i+1]);
        }
        return listBySqlKey(cls, key, params);
    }
}
